package tests;

// A file to represent ProfessorJ style of program design and comment style
// to illustrate the conversion of the program and its test suite to Java
// using the tester library.

/**
 * Copyright 2007, 2008 Viera K. Proulx
 * This program is distributed under the terms of the 
 * GNU Lesser General Public License (LGPL)
 */
/**
 * <p>A class that illustrates the ease of transition from ProfessorJ to 
 * using the <code>tester</code> library.</p>
 * <p>Run it with the file <code>AnyExamples</code>
 */

// Represents a Song for 'iTunes'
class Song{
    String title;
    String artist;
    int size;
    double price;

    Song(String title, String artist, int size, double price){
        this.title = title;
        this.artist = artist;
        this.size = size;
        this.price = price;
    }
}

// Represents a List of Songs...
interface ILoS{
    // Count the number of songs in *this* ILoS
    int count();

    // Count the number of songs in *this* ILoS 
    // by adding to the current count
    int countAcc(int acc);


    // Find the total size of all the songs in *this* ILoS
    int totalSize();

    // Find the total size of all the songs in *this* ILoS 
    // by updating the given size
    int totalSizeAcc(int acc);
    

    // Tell if there is a song by the given artist in *this* ILoS
    boolean contains(String artist);

    // Tell if there is a song by the given artist in *this* ILoS
    // knowing whether it was found already
    // NOTE: here the result can be reported immediately without the accumulator
    boolean containsAcc(String artist, boolean acc);


    // Create a list of all songs by the given artist in *this* ILoS
    ILoS allBy(String artist);

    // Create a list of all songs by the given artist in *this* ILoS
    // adding to the already collected list
    ILoS allByAcc(String artist, ILoS acc);
}

// Represents a List of Songs...
abstract class ALoS implements ILoS{
    // Count the number of songs in *this* ILoS
    public int count(){
      return this.countAcc(0);
    }

    // Count the number of songs in *this* ILoS 
    // by adding to the current count
    public abstract int countAcc(int acc);

    // Find the total size of all the songs in *this* ILoS
    public int totalSize(){
      return this.totalSizeAcc(0);
    }

    // Find the total size of all the songs in *this* ILoS 
    // by updating the given size
    public abstract int totalSizeAcc(int acc);
    

    // Tell if there is a song by the given artist in *this* ILoS
    public boolean contains(String artist){
      return this.containsAcc(artist, false);
    }

    // Tell if there is a song by the given artist in *this* ILoS
    // knowing whether it was found already
    // NOTE: here the result can be reported immediately without the accumulator
    public abstract boolean containsAcc(String artist, boolean acc);

    // Create a list of all songs by the given artist in *this* ILoS
    public ILoS allBy(String artist){
      return this.allByAcc(artist, new MtLoS());
    }

    // Create a list of all songs by the given artist in *this* ILoS
    // adding to the already collected list
    public abstract ILoS allByAcc(String artist, ILoS acc);
}


//Represents an empty List of Songs...
class MtLoS extends ALoS{
 // Nothing to be done for MtLoS
 MtLoS(){}

 // Count the number of songs in *this* ILoS 
 // by adding to the current count
 public int countAcc(int acc){ return acc; }

 // Find the total size of all the songs in *this* ILoS 
 // by updating the given size
 public int totalSizeAcc(int acc){ return acc; }
 
 // Tell if there is a song by the given artist in *this* ILoS
 // knowing whether it was found already
 // NOTE: here the result can be reported immediately without the accumulator
 public boolean containsAcc(String artist, boolean acc){ return acc; }

 // Create a list of all songs by the given artist in *this* ILoS
 // adding to the already collected list
 public ILoS allByAcc(String artist, ILoS acc){ return acc; }
}

//Represents a non-empty List of Songs...
class ConsLoS extends ALoS{
 Song first;
 ILoS rest;

 ConsLoS(Song first, ILoS rest){
     this.first = first;
     this.rest = rest;
 }
 
 /* TEMPLATE
    ... this.first ...         --- Song
    ... this.first.title ...   --- String
    ... this.first.artist ...  --- String
    ... this.first.size ...    --- int
    ... this.first.price ...   --- double
    ... this.rest ...          --- ILoS

    ... this.rest.count() ...           --- int
    ... this.rest.totalSize() ...       --- int
    ... this.rest.contains(String) ...  --- boolean
    ... this.rest.allBy(String) ...     --- ILoS

    ... this.rest.countAcc(int acc) ...                 --- int
    ... this.rest.totalSizeAcc(int acc) ...             --- int
    ... this.rest.containsAcc(String, boolean acc) ...  --- boolean
    ... this.rest.allByAcc(String, ILoS acc) ...        --- ILoS

 */

 // Count the number of songs in *this* ILoS 
 // by adding to the current count
 public int countAcc(int acc){ 
   return this.rest.countAcc(1 + acc);
 }

 // Find the total size of all the songs in *this* ILoS 
 // by updating the given size
 public int totalSizeAcc(int acc){ 
   return this.rest.totalSizeAcc(this.first.size + acc);
 }
 
 // Tell if there is a song by the given artist in *this* ILoS
 // knowing whether it was found already
 // NOTE: here the result can be reported immediately without the accumulator
 public boolean containsAcc(String artist, boolean acc){ 
   return this.rest.containsAcc(artist,
                                this.first.artist.equals(artist) || acc);
 }

 // Create a list of all songs by the given artist in *this* ILoS
 // adding to the already collected list
 public ILoS allByAcc(String artist, ILoS acc){
     if(this.first.artist.equals(artist))
         return this.rest.allByAcc(artist, new ConsLoS(this.first, acc));
     else
         return this.rest.allByAcc(artist, acc);
 }
}

